/*  
*   simple loger
*
*   constructor: if no param then everything is print to stdout
*               otherwise everything goes to file
*
*   TODO: operators, buffering, treshold buffer flush
*/

#include <stdlib.h>
#include <iostream>
#include <ctime>
#include <fstream>
#include <string>
#include "log.h"

#if defined(linux)
  #include <time.h>
#endif

#define BUFFER_SIZE 500

#if defined(WIN32)
#include "windows.h"
int errorlog_t::getms() {
  SYSTEMTIME SystemTime;
  GetSystemTime(&SystemTime);
  return SystemTime.wMilliseconds;
}
#else
int errorlog_t::getms() {
    // "You have to implement your own milisecond display function (int getms()) in log.cc" !
	//microsecs according to POSIX
	
	timespec ts;
	clock_gettime(CLOCK_REALTIME,&ts);
	return ts.tv_nsec / 1000000;
}
#endif

errorlog_t::errorlog_t() {
	file = NULL;
	mode = 0;
	treshold = 2;
	opbuffer = new char[BUFFER_SIZE];
	opbuffer[0] = '\0';
	opbuffer_level = 0;
}
errorlog_t::errorlog_t(const char *to) {
  file = NULL;
	mode = 1;
  fName = to;
  file = new ofstream(fName.c_str(),ios::app);
  file->setf(ios::unitbuf);
  treshold = 2;
	opbuffer = new char[BUFFER_SIZE];
	opbuffer[0] = '\0';
	opbuffer_level = 0;
}

/* 
*  log
*  
*  @params: felel <0;5> (importance felel)
*  { undef, debug, info, warning, error, critical }
*/

void errorlog_t::log() {
     time_t ltime;
     char timestr[80];
     time( &ltime );
	   struct tm *now;

	   now = localtime( &ltime );
	   
	   int ms = getms();
	   
   
	   sprintf(timestr, "%02d:%02d:%02d:%03d", now->tm_hour, now->tm_min, now->tm_sec, ms);
	   treshold = (treshold+opbuffer_level)/2;
    
    
    if(mode) {
      if(strlen(opbuffer)>0) {
        *file << '[' << opbuffer_level << ']' << " @ " << timestr << " >> " << opbuffer << endl;
        opbuffer[0] = '\0';
        opbuffer_level = 0;
      }
     if(opbuffer_level > treshold) *file << flush;
     } else {
       if(strlen(opbuffer)>0) {
        cout << '[' << opbuffer_level << ']' << " @ " << timestr << " >> " << opbuffer << endl;
        opbuffer[0] = '\0';
        opbuffer_level = 0;
       }
    }
}




void errorlog_t::operator_buffer(const char * store) {
       strcat(opbuffer, store);
     }


errorlog_t& errorlog_t::operator << (enum modifiers_e which) {
  if(which == nl) {
  	this->operator_buffer("\n| ");
  } else if(which == fl) {
    this->log();
  } else if(which == empty) {
    opbuffer[0] = '\0';
  } else if(which == critical) {
    opbuffer_level = 5;
  } else if(which == error) {
    opbuffer_level = 4;
  } else if(which == warning) {
    opbuffer_level = 3;
  } else if(which == info) {
    opbuffer_level = 2;
  } else if(which == debug) {
    opbuffer_level = 1;
  } else {
    this->operator_buffer("unknown operator");
  }
	return *this;
}

errorlog_t& errorlog_t::operator << (const char var) {
	char buffer[20];
	sprintf(buffer, "%c", var);
	this->operator_buffer(buffer);
	return *this;
}

errorlog_t& errorlog_t::operator << (const char* var) {
	this->operator_buffer(var);
	return *this;
}
errorlog_t& errorlog_t::operator << (const string var) {
  char buffer[200];
	sprintf(buffer, "%s", var.c_str());
  this->operator_buffer(buffer);
  return *this;
}
errorlog_t& errorlog_t::operator << (const bool var) {
  if(var) 
    this->operator_buffer("TRUE"); 
  else 
    this->operator_buffer("FALSE");
  return *this;
}

errorlog_t& errorlog_t::operator << (const short var) {
  char buffer[7];
	sprintf(buffer, "%dh", (int)var);
	this->operator_buffer(buffer);
	return *this;

}
errorlog_t& errorlog_t::operator << (const unsigned short var) {
  char buffer[6];
	sprintf(buffer, "%uh", (int)var);
	this->operator_buffer(buffer);
	return *this;
}
errorlog_t& errorlog_t::operator << (const int var) {
  char buffer[12];
	sprintf(buffer, "%d", (int)var);
	this->operator_buffer(buffer);
	return *this;
}
errorlog_t& errorlog_t::operator << (const unsigned int var) {
  char buffer[11];
	sprintf(buffer, "%u", (int)var);
	this->operator_buffer(buffer);
	return *this;
}
errorlog_t& errorlog_t::operator << (const long var) {
  char buffer[20];
	sprintf(buffer, "%dl", (int)var);
	this->operator_buffer(buffer);
	return *this;
}
errorlog_t& errorlog_t::operator << (const unsigned long var) {
  char buffer[20];
	sprintf(buffer, "%ul", (int)var);
	this->operator_buffer(buffer);
	return *this;
}
errorlog_t& errorlog_t::operator << (const float var) {
  char buffer[20];
	sprintf(buffer, "%f", (int)var);
	this->operator_buffer(buffer);
	return *this;
}
errorlog_t& errorlog_t::operator << (const double var) {
  char buffer[20];
	sprintf(buffer, "%fl", (int)var);
	this->operator_buffer(buffer);
	return *this;
}
errorlog_t& errorlog_t::operator << (const long double var) {
  char buffer[20];
	sprintf(buffer, "%fL", (int)var);
	this->operator_buffer(buffer);
	return *this;
}
errorlog_t& errorlog_t::operator << (const void* var) {
  char buffer[200];
	sprintf(buffer, "%p", (int)var);
	this->operator_buffer(buffer);
	return *this;
}



errorlog_t::~errorlog_t() {
       if(NULL != file) {
         file->close();
         delete file;
       }
       delete opbuffer;
       
     }

//utkf
